<?php

namespace app\api\service;

use HuaweiCloud\SDK\Live\V1\Model\DeleteDomainMappingRequest;
use HuaweiCloud\SDK\Live\V1\Model\DeleteDomainRequest;
use HuaweiCloud\SDK\Live\V1\Model\ListLiveStreamsOnlineRequest;
use HuaweiCloud\SDK\Live\V1\Model\LiveDomainModifyReq;
use HuaweiCloud\SDK\Live\V1\Model\ShowDomainRequest;
use HuaweiCloud\SDK\Cdn\V1\Model\CreateDomainRequest;
use HuaweiCloud\SDK\Core\Auth\BasicCredentials;
use HuaweiCloud\SDK\Core\Http\HttpConfig;
use HuaweiCloud\SDK\Core\Exceptions\ConnectionException;
use HuaweiCloud\SDK\Core\Exceptions\RequestTimeoutException;
use HuaweiCloud\SDK\Core\Exceptions\ServiceResponseException;
use HuaweiCloud\SDK\Live\V1\LiveClient;
use HuaweiCloud\SDK\Live\V1\Model\CreateDomainMappingRequest;
use HuaweiCloud\SDK\Live\V1\Model\DomainMapping;
use HuaweiCloud\SDK\Live\V1\Model\LiveDomainCreateReq;
use HuaweiCloud\SDK\Live\V1\Model\UpdateDomainRequest;
use think\Exception;

// 华为直播
class HuaWeiLive
{
    protected $ak = "VNMKYZQ8IFYQE5JWZ77U";//华为云帐号Access Key
    protected $sk = "Nwtl3FmJ2k6fPHMOPM9YGRQaOHpV0uH8CbrGW3ZZ";//华为云帐号Secret Access Key

    //直播服务应用区域和各服务的终端节点
    protected $endpoint = "https://live.cn-north-4.myhuaweicloud.com";
    // 直播服务对应区域的项目ID
    protected $projectId = "6907d78c25574d17b16de0d8d8d80738";//云服务所在项目ID ，根据您需要操作的项目所属区域选择对应的项目ID

    protected $client;

    private $push_key = 'TXqCagV62BLAF1tXj8q3F0Eo2na56zHt';//推流防盗链key
    private $push_hw_time = '7200';//时长
    private $pull_key = 'tKYi6ZNUwj8iztSVJWmsC7Isr7tJA77i';//拉流防盗链key
    private $pull_hw_time = '7200';//时长


    public function __construct(){
        $ak = $this->ak;
        $sk = $this->sk;
        $projectId = $this->projectId;
        $endpoint = $this->endpoint;

        //初始化认证信息
        $credentials = new BasicCredentials($ak, $sk, $projectId);//首先需要获取永久AK和SK，以及projectId
        $config = HttpConfig::getDefaultConfig();//配置客户端属性-使用默认配置
        $config->setIgnoreSslVerification(true);

        //初始化直播服务的客户端
        $this->client = LiveClient::newBuilder(new LiveClient)
            ->withHttpConfig($config)
            ->withEndpoint($endpoint)
            ->withCredentials($credentials)
            ->build();
    }

    /**
     * 创建直播域名(推流/拉流(播放域名))
     * @param string $domain 直播域名
     * @param string $domain_type 域名类型|pull:播放域名,push:推流域名
     * @param string $region 直播所属的直播中心|如:cn-north-4
     * @param string $service_area 域名加速区域|mainland_china：中国大陆,outside_mainland_china：中国大陆境外,global：全球加速
     * @param string $enterprise_project_id 企业项目ID
     */
    public function createDomain(string $domain, string $domain_type, string $region = 'cn-north-4', string $service_area = '', string $enterprise_project_id = '')
    {
        $data = [
            'domain'=>$domain,
            'domain_type'=>$domain_type,
            'region'=>$region,
            'service_area'=>$service_area,
            'enterprise_project_id'=>$enterprise_project_id,
        ];
        $obj = $this->client;
        $request = new CreateDomainRequest();
        $body = new LiveDomainCreateReq();
        $body->setDomain($domain);
        $body->setDomainType($domain_type);
        $body->setRegion($region);
        $request->setBody($body);

        $res = [
            'code'=>200,
            'msg'=>'',
            'data'=>[]
        ];

        try {
            $response = $obj->CreateDomain($request);
            $res['msg'] = 'success';
            $res['data'] = json_decode($response,true);

        } catch (ConnectionException $e) {
            $res['code'] = $e->getCode();
            $res['msg'] = $e->getMessage();
        } catch (RequestTimeoutException $e) {
            $res['code'] = $e->getCode();
            $res['msg'] = $e->getMessage();
        } catch (ServiceResponseException $e) {
            $code =  $e->getHttpStatusCode();
            //$request_id =  $e->getRequestId();
            //$error_code =  $e->getErrorCode();
            $msg = $e->getErrorMsg();
            $res['code'] = $code;
            $res['msg'] = $msg;
        }
        return $res;
    }

    /**
     * 域名映射(播放域名关联推流域名)
     * @param string $pull_domain 直播播放域名
     * @param string $push_domain 直播播放域名关联的推流域名
     */
    public function createDomainMapping(string $pull_domain,string $push_domain){
        $request = new CreateDomainMappingRequest();

        $body = new DomainMapping();
        $body->setPushDomain($push_domain);
        $body->setPullDomain($pull_domain);
        $request->setBody($body);

        $res = [
            'code'=>200,
            'msg'=>'',
            'data'=>[]
        ];

        try {
            $response = $this->client->CreateDomainMapping($request);
            $res['msg'] = 'success';
            $res['data'] = json_decode($response,true);
        } catch (ConnectionException $e) {
            $res['code'] = $e->getCode();
            $res['msg'] = $e->getMessage();
        } catch (RequestTimeoutException $e) {
            $res['code'] = $e->getCode();
            $res['msg'] = $e->getMessage();
        } catch (ServiceResponseException $e) {
            $code =  $e->getHttpStatusCode();
            //$request_id =  $e->getRequestId();
            //$error_code =  $e->getErrorCode();
            $msg = $e->getErrorMsg();
            $res['code'] = $code;
            $res['msg'] = $msg;
        }
        return $res;
    }

    /**
     * 删除直播域名映射关系(播放域名与推流域名接触关联关系)
     * @param string $pull_domain 直播播放域名
     * @param string $push_domain 直播推流域名
     * @return array
     */
    public function deleteDomainMapping(string $pull_domain,string $push_domain){
        $request = new DeleteDomainMappingRequest();
        $request->setPullDomain("pull.fupanai.com");
        $request->setPushDomain("push.fupanai.com");
        $res = [
            'code'=>200,
            'msg'=>'',
            'data'=>[]
        ];
        try {
            $response = $this->client->DeleteDomainMapping($request);
            $res['msg'] = 'success';
            $res['data'] = json_decode($response,true);
        } catch (ConnectionException $e) {
            $res['code'] = $e->getCode();
            $res['msg'] = $e->getMessage();
        } catch (RequestTimeoutException $e) {
            $res['code'] = $e->getCode();
            $res['msg'] = $e->getMessage();
        } catch (ServiceResponseException $e) {
            $code =  $e->getHttpStatusCode();
            //$request_id =  $e->getRequestId();
            //$error_code =  $e->getErrorCode();
            $msg = $e->getErrorMsg();
            $res['code'] = $code;
            $res['msg'] = $msg;
        }
        return $res;
    }


    /**
     * 查询直播域名
     * @param string $domain 直播域名，如果不设置此字段，则返回租户所有的域名信息
     * @param string $enterprise_project_id 企业项目ID，如果不设置此字段，则不进行该字段过滤，返回所有域名信息
     */
    public function showDomain(string $domain = '',string $enterprise_project_id = ''){

        $request = new ShowDomainRequest();
        if ($domain){
            $request->setDomain($domain);
        }
        if ($enterprise_project_id){
            $request->setEnterpriseProjectId($enterprise_project_id);
        }
        $res = [
            'code'=>200,
            'msg'=>'',
            'data'=>[]
        ];

        try {
            $response = $this->client->ShowDomain($request);

            $res['msg'] = 'success';
            $res['data'] = json_decode($response,true);
        } catch (ConnectionException $e) {
            $res['code'] = $e->getCode();
            $res['msg'] = $e->getMessage();
        } catch (RequestTimeoutException $e) {
            $res['code'] = $e->getCode();
            $res['msg'] = $e->getMessage();
        } catch (ServiceResponseException $e) {
            $code =  $e->getHttpStatusCode();
            //$request_id =  $e->getRequestId();
            //$error_code =  $e->getErrorCode();
            $msg = $e->getErrorMsg();
            $res['code'] = $code;
            $res['msg'] = $msg;
        }
        return $res;
    }


    /**
     * 修改直播域名状态|启停
     * @param string $domain 直播域名，不允许修改
     * @param string $status 直播域名状态(on:开启,off:关闭)|，通过修改此字段，实现域名的启用和停用；域名处于“配置中”状态时，不允许对该域名执行启停操作
     * @param string $enterprise_project_id
     */
    public function updateDomain(string $domain,string $status = '',string $enterprise_project_id = ''){

        $request = new UpdateDomainRequest();
        $body = new LiveDomainModifyReq();
        $body->setDomain($domain);
        if (in_array($status,['on','off'])){
            $body->setStatus($status);
        }
        if ($enterprise_project_id) {
            $body->setEnterpriseProjectId($enterprise_project_id);
        }
        $request->setBody($body);
        $res = [
            'code'=>200,
            'msg'=>'',
            'data'=>[]
        ];
        try {
            $response = $this->client->UpdateDomain($request);

            $res['msg'] = 'success';
            $res['data'] = json_decode($response,true);
        } catch (ConnectionException $e) {
            $res['code'] = $e->getCode();
            $res['msg'] = $e->getMessage();
        } catch (RequestTimeoutException $e) {
            $res['code'] = $e->getCode();
            $res['msg'] = $e->getMessage();
        } catch (ServiceResponseException $e) {
            $code =  $e->getHttpStatusCode();
            //$request_id =  $e->getRequestId();
            //$error_code =  $e->getErrorCode();
            $msg = $e->getErrorMsg();
            $res['code'] = $code;
            $res['msg'] = $msg;
        }
        return $res;
    }

    /**
     * 删除直播域名(推流/播放域名)
     * @param string $domain 直播域名
     * @return array
     */
    public function deleteDomain(string $domain){
        $request = new DeleteDomainRequest();
        $request->setDomain($domain);
        $res = [
            'code'=>200,
            'msg'=>'',
            'data'=>[]
        ];
        try {
            $response = $this->client->DeleteDomain($request);
            $res['msg'] = 'success';
            $res['data'] = json_decode($response,true);
        } catch (ConnectionException $e) {
            $res['code'] = $e->getCode();
            $res['msg'] = $e->getMessage();
        } catch (RequestTimeoutException $e) {
            $res['code'] = $e->getCode();
            $res['msg'] = $e->getMessage();
        } catch (ServiceResponseException $e) {
            $code =  $e->getHttpStatusCode();
            //$request_id =  $e->getRequestId();
            //$error_code =  $e->getErrorCode();
            $msg = $e->getErrorMsg();
            $res['code'] = $code;
            $res['msg'] = $msg;
        }
        return $res;
    }

    /**
     * 生成鉴权直播URL
     * {推/拉流域名}/{AppName}/{StreamName}|如:push.zeyan.wang/live/test123
     * @param string $url 推/拉流域名
     * @param string $appName appName名
     * @param string $streamName streamName名
     * @param string $type 类型|push:推流,pull:拉流
     * @return string 直播/播放鉴权完整的url
     */
    public function createLiveUrl(string $url,string $appName,string $streamName,string $type){
        //原始URL?hwSecret=hmac_sha256(Key, StreamName + hwTime)&hwTime=hex(timestamp)
        if ($type=='push'){
            $url = "rtmp://{$url}/{$appName}/{$streamName}";
            $key = $this->push_key;
            $hw_time = $this->push_hw_time;
        } else {
            $url = "https://{$url}/{$appName}/{$streamName}.m3u8";
            $key = $this->pull_key;
            $hw_time = $this->pull_hw_time;
        }
        $time = time(); // 获取当前时间戳
        // 转换为十六进制
        $hwTime = dechex($time + $hw_time);
        // 计算鉴权串
        $data = $streamName . $hwTime;
        $hwSecret = hash_hmac('sha256', $data, $key);
        // 构建鉴权URL
        $authURL = "{$url}?hwSecret={$hwSecret}&hwTime={$hwTime}";
        return $authURL;
    }

    //生成鉴权直播URL-测试用
    public function createPushUrl(string $url,string $streamName,string $type){
        //原始URL?hwSecret=hmac_sha256(Key, StreamName + hwTime)&hwTime=hex(timestamp)
        if ($type=='push'){
            $key = $this->push_key;
            $hw_time = $this->push_hw_time;
        } else {
            $key = $this->pull_key;
            $hw_time = $this->pull_hw_time;
        }
        $time = time(); // 获取当前时间戳
        // 转换为十六进制
        $hwTime = dechex($time + $hw_time);
        // 计算鉴权串
        $data = $streamName . $hwTime;
        $hwSecret = hash_hmac('sha256', $data, $key);
        // 构建鉴权URL
        $authURL = "{$url}?hwSecret={$hwSecret}&hwTime={$hwTime}";
        return $authURL;
    }

    /**
     * 查询直播中的流信息
     * 推流URL组成 = rtmp://{推流域名}/{应用名}/{串流名}
     * @param string $publish_domain 推流域名
     * @param string $app 应用名 AppName
     * @param int|null $offset 偏移量,表示从此偏移量开始查询, offset大于等于0
     * @param int|null $limit 每页记录数,取值范围[1,100],默认值10
     * @param string $stream 串流名,用于单流查询,携带stream参数时app不能缺省
     * @return array
     */
    public function listLiveStreamsOnline(string $publish_domain, string $app, int $offset = null, int $limit = null, string $stream = '')
    {
        $request = new ListLiveStreamsOnlineRequest();
        $request->setPublishDomain($publish_domain);
        $request->setApp("live");
        if ($stream){
            $request->setStream($stream);
        }
        if($offset){
            $request->setOffset($offset);
        }
        if ($limit){
            $request->setLimit($limit);
        }

        $res = [
            'code'=>200,
            'msg'=>'',
            'data'=>[]
        ];
        try {
            $response = $this->client->ListLiveStreamsOnline($request);
            $res['msg'] = 'success';
            $res['data'] = json_decode($response,true);
        } catch (ConnectionException $e) {
            $res['code'] = $e->getCode();
            $res['msg'] = $e->getMessage();
        } catch (RequestTimeoutException $e) {
            $res['code'] = $e->getCode();
            $res['msg'] = $e->getMessage();
        } catch (ServiceResponseException $e) {
            $code =  $e->getHttpStatusCode();
            //$request_id =  $e->getRequestId();
            //$error_code =  $e->getErrorCode();
            $msg = $e->getErrorMsg();
            $res['code'] = $code;
            $res['msg'] = $msg;
        }
        return $res;
    }

}
